package com.atguigu.ssyx.activity.service.impl;


import com.atguigu.ssyx.activity.mapper.ActivityInfoMapper;
import com.atguigu.ssyx.activity.mapper.ActivityRuleMapper;
import com.atguigu.ssyx.activity.mapper.ActivitySkuMapper;
import com.atguigu.ssyx.activity.service.IActivityInfoService;
import com.atguigu.ssyx.activity.service.ICouponInfoService;
import com.atguigu.ssyx.client.prouduct.ProductFeignClient;
import com.atguigu.ssyx.enums.ActivityType;
import com.atguigu.ssyx.model.activity.ActivityInfo;
import com.atguigu.ssyx.model.activity.ActivityRule;
import com.atguigu.ssyx.model.activity.ActivitySku;
import com.atguigu.ssyx.model.activity.CouponInfo;
import com.atguigu.ssyx.model.order.CartInfo;
import com.atguigu.ssyx.model.product.SkuInfo;
import com.atguigu.ssyx.vo.activity.ActivityRuleVo;
import com.atguigu.ssyx.vo.order.CartInfoVo;
import com.atguigu.ssyx.vo.order.OrderConfirmVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.jsonwebtoken.lang.Collections;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>
 * 活动表 服务实现类
 * </p>
 *
 * @author author
 * @since 2024-06-30
 */
@Service
@Slf4j
public class ActivityInfoServiceImpl extends ServiceImpl<ActivityInfoMapper, ActivityInfo> implements IActivityInfoService {
    @Autowired
    private ActivityInfoMapper activityInfoMapper;

    @Autowired
    private ActivityRuleMapper activityRuleMapper;

    @Autowired
    private ActivitySkuMapper activitySkuMapper;

    @Autowired
    private ProductFeignClient productFeignClient;
    @Autowired

    private ICouponInfoService couponInfoService;

    @Override
    public IPage<ActivityInfo> selectPage(Page<ActivityInfo> pageParam) {
        QueryWrapper<ActivityInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByDesc("id");

        IPage<ActivityInfo> page = activityInfoMapper.selectPage(pageParam, queryWrapper);

        page.getRecords().stream().forEach(item -> {
            item.setActivityTypeString(item.getActivityType().getComment());
        });
     /*
        枚举类  ActivityType activityType=ActivityType.FULL_REDUCTION;
      1.  activityType.getCode()
        activityType.getComment()
      2.   枚举类的对象就是一个枚举类.枚举值.
       */
        return page;
    }


    //    根据活动id获得活动规则列表
    @Override
    public Map<String, Object> findActivityRuleList(Long id) {
        //        1.根据活动id查询, 查询规则列表
        //        不清楚活动规则列表的与info对应的是那个字段,(getActivityId)
        Map map = new HashMap<String, Object>();

        LambdaQueryWrapper<ActivityRule> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(ActivityRule::getActivityId, id);

        List<ActivityRule> activityRules = activityRuleMapper.selectList(lambdaQueryWrapper);
        map.put("activityRuleList", activityRules);


        //  2.根据活动id查询,获得到规则内的商品表.
        //2.1   根据活动id得到 对应多个商品id  ,  根据多个商品id获得商品列表

        LambdaQueryWrapper<ActivitySku> ActivitySku_LambdaQueryWrapper = new LambdaQueryWrapper<>();
        ActivitySku_LambdaQueryWrapper.eq(ActivitySku::getActivityId, id);
        List<ActivitySku> activitySkuList = activitySkuMapper.selectList(ActivitySku_LambdaQueryWrapper);

        //获得活动下的商品id.
        List<Long> skuIdList = activitySkuList.stream().map(ActivitySku::getSkuId).collect(Collectors.toList());
//        LambdaQueryWrapper<SkuInfo> lambdaQueryWrapper1 = new LambdaQueryWrapper();
//        lambdaQueryWrapper1.eq(SkuInfo::getId, skuIdList);
        if (skuIdList.size() == 0) {
            return map;
        }
        /*
         * 刚才还想着拿到另一个模块的service进行操作数据,结果是哟啊是哟feign把请求的id给另一个模块.
         *  先在feign的接口文件定义好一个抽象方法,对准模块的方法.
         * */
//获得产品模块的商品。
        List<SkuInfo> skuInfoList = productFeignClient.findsSkuInfoList(skuIdList);
        map.put("skuInfoList", skuInfoList);
        return map;
    }

    @Override
    public void saveActivityRule(ActivityRuleVo activityRuleVo) {
//        保存之前先是删除规则和商品的数据
        Long activityId = activityRuleVo.getActivityId();
        //1.规则数据删除
        activityRuleMapper.delete(new LambdaQueryWrapper<ActivityRule>().eq(ActivityRule::getActivityId, activityRuleVo.getActivityId()));

//2.商品数据删除
        activitySkuMapper.delete(new LambdaQueryWrapper<ActivitySku>().eq(ActivitySku::getActivityId, activityRuleVo.getActivityId()));
        List<ActivityRule> activityRuleList = activityRuleVo.getActivityRuleList();
        List<ActivitySku> activitySkuList = activityRuleVo.getActivitySkuList();
        ActivityInfo activityInfo = baseMapper.selectById(activityId);

        for (ActivityRule activityRule : activityRuleList) {
            activityRule.setActivityId(activityId);//活动id
            activityRule.setActivityType(activityInfo.getActivityType());//活动类型
            activityRuleMapper.insert(activityRule);
        }
//删除商品之后添加商品
        for (ActivitySku activitySku : activitySkuList) {
            activitySku.setActivityId(activityRuleVo.getActivityId());
            activitySkuMapper.insert(activitySku);
        }
    }

    @Override
    public List<SkuInfo> findSkuInfoByKeyword(String keyword) {
//        根据关键字查询sku匹配内容.

//        需要我们去product模块查询内容.

//        根据关键字查询出物品,之后拿到id.
        List<SkuInfo> skuInfoByKeyword = productFeignClient.findSkuInfoByKeyword(keyword);
        log.info("skuInfoByKeyword:" + skuInfoByKeyword);
        if (skuInfoByKeyword.size() == 0) {
            return skuInfoByKeyword;
        }
        List<Long> list = skuInfoByKeyword.stream().map(SkuInfo::getId).collect(Collectors.toList());
//        这是已经参与活动的id.
        List<Long> exitsSkuIdList = baseMapper.selectSkuInfoListisExits(list);


//        找出没有在活动中的,之后返回数据.
        List<SkuInfo> findSkuIdList = skuInfoByKeyword.stream().filter(sku -> !exitsSkuIdList.contains(sku.getId())).collect(Collectors.toList());

//如果我们的活动范围有这个商品了,而且在活动时间内,就不要添加.如果没有就需要添加了.
        return findSkuIdList;
    }

    @Override
    public Map<Long, List<String>> findActivity(List<Long> skuIdList) {
        Map<Long, List<String>> result = new HashMap<>();
//    不要在for循环里面查sql.


//        他的思路是,一个商品拿到对应规则.一个商品有多个规则.

        skuIdList.forEach(skuId -> {
//            拿到规则.
            List<ActivityRule> activityRuleList = baseMapper.findActivityRule(skuId);

            if (!Collections.isEmpty(activityRuleList)) {
                List<String> RuleDesc = new ArrayList();
//根据优惠写出商品的描述.
                activityRuleList.stream().forEach(activityRule -> {
                    String ruleDesc = getRuleDesc(activityRule);
                    activityRule.setRuleDesc(ruleDesc);
//把规则desc写入一个对象的规则字段中.
                    RuleDesc.add(ruleDesc);
                });
                result.put(skuId, RuleDesc);
            }
        });


        return result;
    }


    //构造规则名称的方法
    private String getRuleDesc(ActivityRule activityRule) {
        ActivityType activityType = activityRule.getActivityType();
        StringBuffer ruleDesc = new StringBuffer();
        if (activityType == ActivityType.FULL_REDUCTION) {
            ruleDesc.append("满").append(activityRule.getConditionAmount()).append("元减").append(activityRule.getBenefitAmount()).append("元");
        } else {
            ruleDesc.append("满").append(activityRule.getConditionNum()).append("元打").append(activityRule.getBenefitDiscount()).append("折");
        }
        return ruleDesc.toString();
    }


    //获得这个商品的优惠券信息和营销信息。
    @Override
    public Map<String, Object> findActivityAndCoupon(Long skuId, Long userId) {
        //获得活动的信息。
        List<ActivityRule> activityRule = baseMapper.findActivityRule(skuId);
        //获得优惠券信息
        List<CouponInfo> couponInfoList = couponInfoService.findCouponInfoList(skuId, userId);

        HashMap<String, Object> stringObjectHashMap = new HashMap<String, Object>();
        stringObjectHashMap.put("activityRule", activityRule);
        stringObjectHashMap.put("couponInfoList", couponInfoList);
        return stringObjectHashMap;
    }

    @Override
    public OrderConfirmVo findCartActivityAndCoupon(List<CartInfo> cartInfoList, Long userId) {
//      1.      拿到购物车的每一项目,之后拿到活动信息的活动规则.根据活动规则分组.
        List<CartInfoVo> cartActivityList = this.findCartActivityList(cartInfoList);
        BigDecimal count = new BigDecimal(0);

//     2.        计算参与活动优惠后的金额.
        BigDecimal reduceAmount = cartActivityList.stream().filter(item -> item.getActivityRule() != null).map(cartActivity -> cartActivity.getActivityRule().getReduceAmount()).reduce(BigDecimal.ZERO, BigDecimal::add);


//3.     获得购物车里面的优惠券列表.
        /**
         * 优惠券金额里面有一个最优优惠情况属性.couponInfoList返回优惠券。
         */
        //用户领取过什么优惠券.
        List<CartInfo> collect = cartInfoList.stream()
                .filter(cartInfo -> cartInfo.getIsChecked() == 1).collect(Collectors.toList());
        List<CouponInfo> couponInfoList = couponInfoService.findCartCouponInfo(collect, userId);

//        4.计算优惠券之后金额,一次使用一张.     只能只用一张.得出使用了优惠券之后是多少钱.
        BigDecimal couponreduce = new BigDecimal(0);
        if (!Collections.isEmpty(couponInfoList)) {
//            优惠券金额
            couponreduce = couponInfoList
                    .stream()
                    .filter(item -> item.getIsOptimal().intValue() == 1)
                    .map(couponInfo -> couponInfo.getAmount()).reduce(BigDecimal.ZERO, BigDecimal::add);
        }

//        这种最优优惠券
//        5.没有使用优惠券和活动的商品.
        BigDecimal originalTotalAmount = cartInfoList.stream()
                .filter(cartInfo -> cartInfo.getIsChecked() == 1).map(cartInfo -> cartInfo.getCartPrice().multiply(new BigDecimal(cartInfo.getSkuNum()))).reduce(BigDecimal.ZERO, BigDecimal::add);
//        6.参与活动和优惠券金额减去总数.
        BigDecimal totalreduce = originalTotalAmount.subtract(couponreduce).subtract(reduceAmount);

//        7.OrderConfirmVo.返回.
        OrderConfirmVo orderTradeVo = new OrderConfirmVo();
        orderTradeVo.setCarInfoVoList(cartActivityList);
        orderTradeVo.setActivityReduceAmount(reduceAmount);
        orderTradeVo.setCouponInfoList(couponInfoList);
        orderTradeVo.setCouponReduceAmount(couponreduce);
        orderTradeVo.setOriginalTotalAmount(originalTotalAmount);
        orderTradeVo.setTotalAmount(totalreduce);
        return orderTradeVo;
//   分组后的活动id, 拿到他们的活动规则.
    }


    /**
     * CartInfoVo里面需要这个活动规则和商品.
     *
     * @param cartInfoList
     */
    @Override
    public List<CartInfoVo> findCartActivityList(List<CartInfo> cartInfoList) {
//所有购物车数据.
        List<CartInfoVo> cartInfoVoList = new ArrayList<>();

//        购物车里面所有的skuId.
        List<Long> collect = cartInfoList.stream().map(cartInfo -> cartInfo.getSkuId()).collect(Collectors.toList());

//          获得购物车所有的活动id.
//        可能是五个商品,两个活动. 返回活动id和skuid.
        List<ActivityRule> activityRules = baseMapper.selectCartActivity(collect);
//        进行分组,一个活动id对应多个skuId.     Long是一个活动id,set是一个商品集合.
        /**
         *
         * 获得所有活动下的skuid
         */
        Map<Long, Set<Long>> activityIdToSkuIdListMap = activityRules.stream().collect(Collectors.groupingBy(ActivityRule::getActivityId, Collectors.mapping(ActivityRule::getSkuId, Collectors.toSet())));

        Set<Long> activitySkuIdSet = new HashSet<>();
//          所有的活动id.
        Set<Long> activityIdSet = activityRules.stream().map(ActivityRule::getActivityId).collect(Collectors.toSet());

        Map<Long, List<ActivityRule>> activityRuleGroupMap = null;
//有活动
        if (!Collections.isEmpty(activityIdSet)) {
            LambdaQueryWrapper<ActivityRule> objectLambdaQueryWrapper = new LambdaQueryWrapper<>();
            objectLambdaQueryWrapper.orderByDesc(ActivityRule::getConditionAmount);
            objectLambdaQueryWrapper.in(ActivityRule::getActivityId, activityIdSet);
            List<ActivityRule> activityRules1 = baseMapper.selectCartActivity(collect);
//根据活动id,把优惠进行分组.
//            根据活动进行规则分组.
            activityRuleGroupMap = activityRules1.stream().collect(Collectors.groupingBy(ActivityRule::getActivityId));
//            总结:获得购物车下的活动信息,活动信息的优惠规则.

//          staart   选出 有活动的购物skuId
            Iterator<Map.Entry<Long, Set<Long>>> iterator = activityIdToSkuIdListMap.entrySet().iterator();

//              nentry使用为可以遍历,在HashMap是不可以遍历的,只能通过GetKey()获得value.

//                这里存储的是购物车中,有活动的数据.
            List<CartInfo> currentActivityCartInfoList = null;
//            遍历活动--skudilist的map.
            while (iterator.hasNext()) {
//                遍历每一个活动.
                Map.Entry<Long, Set<Long>> next = iterator.next();
//                key
                Long activityId = next.getKey();
//                value
                Set<Long> value = next.getValue();
//              一个是购物车数据  一个是有活动的数据.

//   当前活动对应的购物项列表
                currentActivityCartInfoList = cartInfoList.stream().filter(cartInfo -> value.contains(cartInfo.getSkuId())).collect(Collectors.toList());

                //当前参与活动商品的总金额
                BigDecimal activityTotalAmount = this.computeTotalAmount(currentActivityCartInfoList);
                //当前活动的购物项总个数
                Integer activityTotalNum = this.computeCartNum(currentActivityCartInfoList);
//拿到这个活动里面的数据.一个购物车有多个活动在.一个个遍历.

                List<ActivityRule> activityRules2 = activityRuleGroupMap.get(activityId);
                ActivityType activityType = activityRules2.get(0).getActivityType();
                ActivityRule activityRule = null;
                if (activityType == ActivityType.FULL_REDUCTION) {
//    满减
                    activityRule = this.computeFullReduction(activityTotalAmount, activityRules2);
                } else if (activityType == ActivityType.FULL_DISCOUNT) {
//      满量
                    activityRule = this.computeFullDiscount(activityTotalNum, activityTotalAmount, activityRules2);
                }
                //同一活动对应的购物项列表与对应优化规则.
                CartInfoVo carInfoVo = new CartInfoVo();
//                获得规则
                carInfoVo.setActivityRule(activityRule);
//                获得参与的sku
                carInfoVo.setCartInfoList(currentActivityCartInfoList);
//对应着一个
                cartInfoVoList.add(carInfoVo);
                //记录,用来获得没有获得的购物车数据.
                activitySkuIdSet.addAll(value);
            }
//   end

//            获得活动下的购物车id.
//            获得活动下的活动规则.

//            无活动的购物skuId
            collect.removeAll(activitySkuIdSet);
            Map<Long, CartInfo> ShopcartIdToInfoMap = null;
//            获得所有的购物车数据
            if (!CollectionUtils.isEmpty(collect)) {
                ShopcartIdToInfoMap = cartInfoList.stream().collect(Collectors.toMap(CartInfo::getSkuId, CartInfo -> CartInfo));
            }
//            没有获得的购物车数据.
            for (Long skuId : collect) {
                CartInfoVo carInfoVo = new CartInfoVo();
                carInfoVo.setActivityRule(null);
                List<CartInfo> currentCartInfoList = new ArrayList<>();
                currentCartInfoList.add(ShopcartIdToInfoMap.get(skuId));
                carInfoVo.setCartInfoList(currentCartInfoList);
                cartInfoVoList.add(carInfoVo);
            }
        }
        return cartInfoVoList;
    }

    /**
     * 计算满量打折最优规则
     *
     * @param totalNum
     * @param activityRuleList //该活动规则skuActivityRuleList数据，已经按照优惠折扣从大到小排序了
     */
    private ActivityRule computeFullDiscount(Integer totalNum, BigDecimal totalAmount, List<ActivityRule> activityRuleList) {
        ActivityRule optimalActivityRule = null;
        //该活动规则skuActivityRuleList数据，已经按照优惠金额从大到小排序了
        for (ActivityRule activityRule : activityRuleList) {
            //如果订单项购买个数大于等于满减件数，则优化打折
            if (totalNum.intValue() >= activityRule.getConditionNum()) {
                BigDecimal skuDiscountTotalAmount = totalAmount.multiply(activityRule.getBenefitDiscount().divide(new BigDecimal("10")));
                BigDecimal reduceAmount = totalAmount.subtract(skuDiscountTotalAmount);
                activityRule.setReduceAmount(reduceAmount);
                optimalActivityRule = activityRule;
                break;
            }
        }
        if (null == optimalActivityRule) {
            //如果没有满足条件的取最小满足条件的一项
            optimalActivityRule = activityRuleList.get(activityRuleList.size() - 1);
            optimalActivityRule.setReduceAmount(new BigDecimal("0"));
            optimalActivityRule.setSelectType(1);
            StringBuffer ruleDesc = new StringBuffer().append("满").append(optimalActivityRule.getConditionNum()).append("元打").append(optimalActivityRule.getBenefitDiscount()).append("折，还差").append(totalNum - optimalActivityRule.getConditionNum()).append("件");
            optimalActivityRule.setRuleDesc(ruleDesc.toString());
        } else {
            StringBuffer ruleDesc = new StringBuffer().append("满").append(optimalActivityRule.getConditionNum()).append("元打").append(optimalActivityRule.getBenefitDiscount()).append("折，已减").append(optimalActivityRule.getReduceAmount()).append("元");
            optimalActivityRule.setRuleDesc(ruleDesc.toString());
            optimalActivityRule.setSelectType(2);
        }
        return optimalActivityRule;
    }

    private BigDecimal computeTotalAmount(List<CartInfo> cartInfoList) {
        BigDecimal total = new BigDecimal("0");
        for (CartInfo cartInfo : cartInfoList) {
            //是否选中
            if (cartInfo.getIsChecked().intValue() == 1) {
                BigDecimal itemTotal = cartInfo.getCartPrice().multiply(new BigDecimal(cartInfo.getSkuNum()));
                total = total.add(itemTotal);
            }
        }
        return total;
    }

    private int computeCartNum(List<CartInfo> cartInfoList) {
        int total = 0;
        for (CartInfo cartInfo : cartInfoList) {
            //是否选中
            if (cartInfo.getIsChecked().intValue() == 1) {
                total += cartInfo.getSkuNum();
            }
        }
        return total;
    }

    /**
     * 计算满减最优规则
     *
     * @param totalAmount
     * @param activityRuleList //该活动规则skuActivityRuleList数据，已经按照优惠金额从大到小排序了
     */
    private ActivityRule computeFullReduction(BigDecimal totalAmount, List<ActivityRule> activityRuleList) {
        ActivityRule optimalActivityRule = null;
        //该活动规则skuActivityRuleList数据，已经按照优惠金额从大到小排序了
        for (ActivityRule activityRule : activityRuleList) {
            //如果订单项金额大于等于满减金额，则优惠金额
            if (totalAmount.compareTo(activityRule.getConditionAmount()) > -1) {
                //优惠后减少金额
                activityRule.setReduceAmount(activityRule.getBenefitAmount());
                optimalActivityRule = activityRule;
                break;
            }
        }
        if (null == optimalActivityRule) {
            //如果没有满足条件的取最小满足条件的一项
            optimalActivityRule = activityRuleList.get(activityRuleList.size() - 1);
            optimalActivityRule.setReduceAmount(new BigDecimal("0"));
            optimalActivityRule.setSelectType(1);

            StringBuffer ruleDesc = new StringBuffer().append("满").append(optimalActivityRule.getConditionAmount()).append("元减").append(optimalActivityRule.getBenefitAmount()).append("元，还差").append(totalAmount.subtract(optimalActivityRule.getConditionAmount())).append("元");
            optimalActivityRule.setRuleDesc(ruleDesc.toString());
        } else {
            StringBuffer ruleDesc = new StringBuffer().append("满").append(optimalActivityRule.getConditionAmount()).append("元减").append(optimalActivityRule.getBenefitAmount()).append("元，已减").append(optimalActivityRule.getReduceAmount()).append("元");
            optimalActivityRule.setRuleDesc(ruleDesc.toString());
            optimalActivityRule.setSelectType(2);
        }
        return optimalActivityRule;
    }


}
